<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { fetchRegister, fetchSendCaptcha } from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { useCaptcha } from '@/hooks/business/captcha';
import { getServiceBaseURL } from '@/utils/service';
import { $t } from '@/locales';

// 注册模块需要用到的接口
// /auth/register 注册接口(email注册时传入email，phone注册时传入phone)
// /auth/sendCaptcha 发送验证码接口 (一并传入图形验证码)(email注册时传入email，phone注册时传入phone)

// 密码加密相关辅助函数
// 将字符串转换为ArrayBuffer
function strToBuffer(str: string): ArrayBuffer {
  const encoder = new TextEncoder();
  return encoder.encode(str).buffer;
}

// 将ArrayBuffer转换为十六进制字符串
function bufferToHex(buffer: ArrayBuffer): string {
  return Array.from(new Uint8Array(buffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

// 密码哈希函数 (SHA-256)
async function hashPassword(password: string): Promise<string> {
  const buffer = strToBuffer(password);
  const hash = await crypto.subtle.digest('SHA-256', buffer);
  return bufferToHex(hash);
}

// 数据加密函数 (AES-GCM)
async function encryptData(data: string, key: string): Promise<string> {
  // 确保密钥是16字节
  const keyBuffer = strToBuffer(key.padEnd(16, '0').substring(0, 16));
  const cryptoKey = await crypto.subtle.importKey('raw', keyBuffer, { name: 'AES-GCM' }, false, ['encrypt']);

  // 生成随机IV (12字节)
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const dataBuffer = strToBuffer(data);

  const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, cryptoKey, dataBuffer);

  // 将IV和加密数据合并并转换为十六进制
  const combined = new Uint8Array(iv.length + encryptedBuffer.byteLength);
  combined.set(iv);
  combined.set(new Uint8Array(encryptedBuffer), iv.length);
  return bufferToHex(combined.buffer);
}

// 密码加密主函数
async function encryptPassword(password: string): Promise<string> {
  try {
    // 先哈希密码
    const hashedPassword = await hashPassword(password);
    // 生成时间戳密钥
    const timestampKey = Math.floor(Date.now() / 30000).toString();
    // 加密哈希后的密码
    const encrypted = await encryptData(hashedPassword, timestampKey);
    return encrypted;
  } catch {
    // 生产环境中可以使用错误监控系统
    throw new Error('Password encryption failed');
  }
}

defineOptions({
  name: 'Register'
});

const { toggleLoginModule } = useRouterPush();
const { formRef, validate } = useNaiveForm();
const { label, isCounting, loading, getCaptcha } = useCaptcha();
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);

// 添加登录类型枚举
enum LoginType {
  Phone = 'phone',
  Email = 'email'
}

interface FormModel {
  account: string;
  captcha: string;
  password: string;
  confirmPassword: string;
}

const model: FormModel = reactive({
  account: '',
  captcha: '',
  password: '',
  confirmPassword: ''
});

// 当前登录类型
const loginType = ref(LoginType.Phone);

// 图像验证码相关状态
const showCaptchaModal = ref(false);
const imageCaptchaValue = ref('');
const imageCaptchaData = reactive({ src: `${baseURL}/api/getCaptcha` });
// const _captchaToken = ref(''); // 已移除未使用的变量

const rules = computed<Record<keyof FormModel, App.Global.FormRule[]>>(() => {
  const { formRules, createConfirmPwdRule } = useFormRules();

  return {
    account: loginType.value === LoginType.Phone ? formRules.phone : formRules.email,
    captcha: formRules.code,
    password: formRules.pwd,
    confirmPassword: createConfirmPwdRule(model.password)
  };
});

// 切换登录类型
function toggleLoginType() {
  loginType.value = loginType.value === LoginType.Phone ? LoginType.Email : LoginType.Phone;
  model.account = '';
  model.captcha = '';
}

// 刷新图像验证码
function refreshImageCaptcha() {
  const timestamp = new Date().getTime();
  imageCaptchaData.src = `${baseURL}/api/getCaptcha?t=${timestamp}`;
  imageCaptchaValue.value = '';
}

// 处理获取验证码按钮点击
function handleGetCaptcha() {
  // 先验证账号格式
  if (model.account.trim() === '') {
    window.$message?.error?.(
      loginType.value === LoginType.Phone ? $t('form.phone.required') : $t('form.email.required')
    );
    return;
  }

  // 根据类型验证格式
  const isPhone = loginType.value === LoginType.Phone;
  const isValid = isPhone ? /^1[3-9]\d{9}$/.test(model.account) : /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(model.account);

  if (!isValid) {
    window.$message?.error?.(isPhone ? $t('form.phone.invalid') : $t('form.email.invalid'));
    return;
  }

  // 显示图像验证码弹窗
  refreshImageCaptcha();
  showCaptchaModal.value = true;
}

// 验证图像验证码并获取短信验证码
async function verifyImageCaptcha() {
  if (!imageCaptchaValue.value.trim()) {
    window.$message?.error?.(isPhone ? $t('form.phone.required') : $t('form.email.required'));
    return;
  }

  try {
    // 无论API调用结果如何，都先关闭弹出层
    showCaptchaModal.value = false;
    
    // 构建请求参数
    const params =
      loginType.value === LoginType.Phone
        ? { phone: model.account, captcha: imageCaptchaValue.value }
        : { email: model.account, captcha: imageCaptchaValue.value };

    // 调用发送验证码API并获取响应
    const response = await fetchSendCaptcha(params);

    // 根据API返回的code处理不同情况
    if (response.code === 0) {
      // 调用获取验证码的函数，传递账号、类型和倒计时时间
      await getCaptcha(model.account, {
        type: loginType.value,
        waitSeconds: response.data?.waitSeconds || 60 // 使用返回的waitSeconds参数，默认60秒
      });
      window.$message?.success?.(isPhone ? $t('page.login.codeLogin.sendCodeSuccess') : $t('page.login.codeLogin.sendCodeSuccess'));
    } else {
      // 显示错误消息，包含API返回的msg
      window.$message?.error?.(response.msg || (isPhone ? $t('form.phone.required') : $t('form.email.required')));
      refreshImageCaptcha();
    }
  } catch (error: any) {
    // 处理网络错误或其他异常
    window.$message?.error?.(
      error.response?.data?.msg || (isPhone ? $t('form.phone.required') : $t('form.email.required'))
    );
    refreshImageCaptcha();
  }
}

async function handleSubmit() {
  await validate();

  try {
    // 加密密码
    const encryptedPassword = await encryptPassword(model.password);
    const encryptedConfirmPassword = await encryptPassword(model.confirmPassword);

    // 构建注册请求参数
    const registerParams = {
      ...(loginType.value === LoginType.Phone ? { phone: model.account } : { email: model.account }),
      captcha: model.captcha,
      password: encryptedPassword,
      confirm_password: encryptedConfirmPassword
    };

    // 发送注册请求
    await fetchRegister(registerParams);

    window.$message?.success($t('page.login.register.success'));
    // 注册成功后可以跳转登录页面或其他操作
  } catch (error) {
    window.$message?.error($t('page.login.register.failed'));
    // console.error('Registration failed:', error);
  }
}
</script>

<template>
  <NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
    <div class="account-input-wrapper">
      <div class="login-type-toggle">
        <div class="toggle-tab" :class="[{ active: loginType === LoginType.Phone }]" @click="toggleLoginType">
          {{ $t('page.login.common.phone') }}
        </div>
        <div class="toggle-tab" :class="[{ active: loginType === LoginType.Email }]" @click="toggleLoginType">
          {{ $t('page.login.common.email') }}
        </div>
      </div>
      <NFormItem path="account">
        <NInput
          v-model:value="model.account"
          :placeholder="
            loginType === LoginType.Phone
              ? $t('page.login.common.phonePlaceholder')
              : $t('page.login.common.emailPlaceholder')
          "
        />
      </NFormItem>
    </div>
    <NFormItem path="captcha">
      <div class="w-full flex-y-center gap-16px">
        <NInput v-model:value="model.captcha" :placeholder="$t('page.login.common.codePlaceholder')" />
        <NButton size="large" :disabled="isCounting" :loading="loading" @click="handleGetCaptcha">
          {{ label }}
        </NButton>
      </div>
    </NFormItem>
    <NFormItem path="password">
      <NInput
        v-model:value="model.password"
        type="password"
        show-password-on="click"
        :placeholder="$t('page.login.common.passwordPlaceholder')"
      />
    </NFormItem>
    <NFormItem path="confirmPassword">
      <NInput
        v-model:value="model.confirmPassword"
        type="password"
        show-password-on="click"
        :placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
      />
    </NFormItem>
    <NSpace vertical :size="18" class="w-full">
      <NButton type="primary" size="large" round block @click="handleSubmit">
        {{ $t('common.confirm') }}
      </NButton>
      <NButton size="large" round block @click="toggleLoginModule('pwd-login')">
        {{ $t('page.login.common.back') }}
      </NButton>
    </NSpace>
  </NForm>

  <!-- 图像验证码弹窗 -->
  <NModal
    v-model:show="showCaptchaModal"
    :close-on-esc="true"
    preset="dialog"
    title="验证图片验证码"
    :close-on-click-overlay="false"
  >
    <div class="captcha-modal">
      <div class="captcha-image-container">
        <img :src="imageCaptchaData.src" alt="验证码" class="captcha-image" @click="refreshImageCaptcha" />
        <!-- <span class="captcha-hint">{{ $t('page.login.common.clickToRefresh') }}</span> -->
      </div>
      <div class="captcha-input-container">
        <NInput
          v-model:value="imageCaptchaValue"
          :placeholder="$t('page.login.common.enterCaptcha')"
          class="captcha-input"
          @keyup.enter="verifyImageCaptcha"
        />
      </div>
      <div class="captcha-button-container">
        <NSpace>
          <NButton @click="showCaptchaModal = false">
            {{ $t('common.cancel') }}
          </NButton>
          <NButton type="primary" @click="verifyImageCaptcha">
            {{ $t('common.confirm') }}
          </NButton>
        </NSpace>
      </div>
    </div>
  </NModal>
</template>

<style scoped>
.captcha-modal {
  text-align: center;
  padding: 16px 24px;
  width: 320px;
  box-sizing: border-box;
}

.captcha-image-container {
  margin-bottom: 8px;
}

.captcha-hint {
  font-size: 12px;
  color: #999;
  display: block;
  margin-top: 8px;
}

.account-input-wrapper {
  margin-bottom: 24px;
}

.login-type-toggle {
  display: flex;
  border-radius: 8px;
  background-color: #f5f7fa;
  padding: 4px;
  margin-bottom: 16px;
  width: 100%;
  max-width: 320px;
  margin-left: auto;
  margin-right: auto;
}

.toggle-tab {
  flex: 1;
  text-align: center;
  padding: 8px 16px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.3s ease;
  color: #666;
  background-color: transparent;
}

.toggle-tab:hover {
  color: #1890ff;
}

.toggle-tab.active {
  background-color: #fff;
  color: #1890ff;
  box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
  font-weight: 600;
}

.captcha-image {
  cursor: pointer;
  width: 200px;
  height: 60px;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
}

.captcha-button-container {
  margin-top: 20px;
  display: flex;
  justify-content: center;
  gap: 12px;
}

.captcha-input {
  margin-top: 16px;
}
</style>
